package com.project.common.core.utils;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class DateUtil {

    public static final String[] YEAR_MONTHS = new String[]{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};

    public static final String[] CHINA_MONTHS = new String[]{"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};

    public static final String[] DAY_HOURS = new String[]{"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"};

    public static final String[] MONTH_DAYS = new String[]{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"};

    /**
     * 判断当前日期是星期几(返回int)
     *
     * @param date 修要判断的时间
     * @return dayForWeek 判断结果
     * @throws Exception 发生异常
     */
    public static int getWeekDayOfnow(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int i = c.get(Calendar.DAY_OF_WEEK) - 1;
        int time = 0;
        switch (i) {
            case 0:
                time = 7;
                break;
            case 1:
                time = 1;
                break;
            case 2:
                time = 2;
                break;
            case 3:
                time = 3;
                break;
            case 4:
                time = 4;
                break;
            case 5:
                time = 5;
                break;
            case 6:
                time = 6;
                break;
            default:
                time = 1;
                break;
        }
        return time;
    }

    /**
     * 生成多层日期目录
     *
     * @param level 目录层数(最多3层)即:月(200906)-日(0605)-时(01)
     * @return
     */
    public static String generateDateDir(int level) {
        if (level < 1 || level > 3)
            level = 3;// 默认3
        SimpleDateFormat levelOne = new SimpleDateFormat("yyyyMM");
        SimpleDateFormat levelTwo = new SimpleDateFormat("MMdd");
        SimpleDateFormat levelThree = new SimpleDateFormat("HH");
        String s = "/";
        String destDirectory = "";
        Date date = new Date(System.currentTimeMillis());
        switch (level) {
            case 1:
                destDirectory += levelOne.format(date);
                break;
            case 2:
                destDirectory += levelOne.format(date) + s + levelTwo.format(date);
                break;
            case 3:
                destDirectory += levelOne.format(date) + s + levelTwo.format(date) + s + levelThree.format(date);
                break;
        }
        return destDirectory;
    }

    /**
     * 获取年
     *
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        return getValue(date, Calendar.YEAR);
    }

    /**
     * 获取月
     *
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        return getValue(date, Calendar.MONTH);
    }

    /**
     * 获取星期
     *
     * @param date
     * @return
     */
    public static int getWeek(Date date) {
        return getValue(date, Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取日
     *
     * @param date
     * @return
     */
    public static int getDay(Date date) {
        return getValue(date, Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取小时
     *
     * @param date
     * @return
     */
    public static int getHour(Date date) {
        return getValue(date, Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取分钟
     *
     * @param date
     * @return
     */
    public static int getMinute(Date date) {
        return getValue(date, Calendar.MINUTE);
    }

    /**
     * 获取分钟
     *
     * @param date
     * @return
     */
    public static int getSecond(Date date) {
        return getValue(date, Calendar.SECOND);
    }

    /**
     * @param date
     * @param field
     * @return
     */
    private static int getValue(Date date, int field) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime());
        return calendar.get(field);
    }

    /**
     * 解析日期
     *
     * @param strDate
     * @return
     * @throws ParseException
     */
    public static Date convertStrToDate(String strDate, String pattern) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            return sdf.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串转calendar
     *
     * @param date    日期的字符串
     * @param pattern 日期的格式
     * @return
     */
    public static Calendar convertStrToCalendar(String date, String pattern) {
        Calendar calendar = null;
        try {
            calendar = Calendar.getInstance();
            SimpleDateFormat format = new SimpleDateFormat(pattern);
            calendar.setTime(format.parse(date));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return calendar;
    }

    /**
     * 格式化date为指定的格式字符串
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String convertDateToStr(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 转换日期为字符串
     *
     * @param date
     * @return
     */
    public static String convertDateToYMDStr(Date date) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd").format(date);
    }

    /**
     * 给日期增加值
     *
     * @param date
     * @param field
     * @param amount
     * @return
     */
    public static Date add(Date date, int field, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime());
        calendar.add(field, amount);
        return new Date(calendar.getTimeInMillis());
    }

    /**
     * 取上个月的第一天
     */
    public static Calendar getLastMonFirstDay(Calendar calendar) {
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        if (month > 0) {
            month--;
        } else {
            year--;
            month = 11;
        }
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar;
    }

    /**
     * 取上个月的最后一天
     */
    public static Calendar getLastMonLastDay(Calendar calendar) {
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        return calendar;
    }

    /**
     * 取得上一天
     */
    public static Calendar getLastDay(Calendar calendar) {
        calendar.add(Calendar.DAY_OF_YEAR, -1);
        return calendar;
    }

    /**
     * 取上个周的最后一天
     */
    public static Calendar getLastweekLastDay(Calendar calendar) {
        calendar.add(Calendar.SUNDAY, -7);
        return calendar;
    }

    /**
     * 取一天中最大时间 毫秒为999
     *
     * @param day
     * @return
     * @throws ParseException
     */
    public static Date getEndOfDay(Date day) {

        if (day == null) {
            day = new Date();
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMaximum(Calendar.MILLISECOND));

        return cal.getTime();
    }

    /**
     * 取一天中最大时间 毫秒为0
     *
     * @param day
     * @return
     * @throws ParseException
     */
    public static Date getEndZeroMillOfDay(Date day) {

        if (day == null) {
            day = new Date();
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime();
    }

    /**
     * 取一天中最小时间
     *
     * @param day
     * @return
     * @throws ParseException
     */
    public static Date getStartOfDay(Date day) {

        if (day == null) {
            day = new Date();
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));

        return cal.getTime();
    }

    /**
     * 取今天的最小时间
     *
     * @return
     * @throws ParseException
     */
    public static Date getTodayStart() {
        return getStartOfDay(new Date());
    }


    /**
     * 计算两个日期之间相差的天数
     *
     * @param startDate 较小的时间
     * @param endDate   较大的时间
     * @return 相差天数
     */
    public static int daysBetween(Date startDate, Date endDate) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(startDate);
        long time1 = cal.getTimeInMillis();
        cal.setTime(endDate);
        long time2 = cal.getTimeInMillis();
        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(betweenDays));
    }

    /**
     * 获取当前月份天数的数组
     *
     * @return
     */
    public static String[] getCurrentMonthDaysArray() {
        return getMonthDaysArray(new Date());
    }

    /**
     * 获取指定月份天数的数组
     *
     * @return
     */
    public static String[] getMonthDaysArray(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        String[] array = new String[maxDay];
        System.arraycopy(MONTH_DAYS, 0, array, 0, maxDay);
        return array;
    }

    /**
     * 获取当前月的第一天
     *
     * @return
     */
    public static Date getCurrentFirstDayOfMonth() {
        return getFirstDayOfMonth(new Date());
    }

    /**
     * 获取当前月的
     *
     * @return
     */
    public static Date getCurrentLastDayOfMonth() {
        return getLastDayOfMonth(new Date());
    }

    /**
     * 获取指定时间中月的第一天
     *
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取指定时间中月的
     *
     * @return
     */
    public static Date getLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 获取当前年的第一天
     *
     * @return
     */
    public static Date getCurrentFirstDayOfYear() {
        return getFirstDayOfYear(new Date());
    }

    /**
     * 获取指定年份的第一天
     *
     * @return
     */
    public static Date getFirstDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取昨天时间
     *
     * @return
     */
    public static Date getYesterday() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    /**
     * 获取前一天
     *
     * @return
     */
    public static Date getYesterday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    /**
     * 获取后一天
     *
     * @return
     */
    public static Date getTomorrow(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, 1);
        return cal.getTime();
    }

    /**
     * 获取前一个月
     *
     * @return
     */
    public static Date getLastMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        return cal.getTime();
    }

    /**
     * 获取后一个月
     *
     * @return
     */
    public static Date getNextMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 1);
        return cal.getTime();
    }

    /**
     * 获取大写的月份
     *
     * @param date
     * @return
     */
    public static String getChinaMonth(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return CHINA_MONTHS[instance.get(Calendar.MONTH)];
    }

    /**
     * 比较两个时间的时分
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int compareToHourMin(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar1.set(Calendar.SECOND, 0);

        Calendar temp = Calendar.getInstance();
        temp.setTime(date2);

        Calendar calendar2 = (Calendar) calendar1.clone();
        calendar2.set(Calendar.HOUR_OF_DAY, temp.get(Calendar.HOUR_OF_DAY));
        calendar2.set(Calendar.MINUTE, temp.get(Calendar.MINUTE));
        calendar2.set(Calendar.SECOND, 0);

        return calendar1.compareTo(calendar2);
    }

    /**
     * 计算两个日期是否是一周(周一作为一周的开始时间)
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameWeek(Date date1, Date date2) {

        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar1.setFirstDayOfWeek(Calendar.MONDAY);

        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        calendar2.setFirstDayOfWeek(Calendar.MONDAY);

        if (calendar1.get(Calendar.WEEK_OF_YEAR) == calendar2.get(Calendar.WEEK_OF_YEAR)) {
            return true;
        }

        return false;
    }

    /**
     * 根据开始时间和结束时间返回时间段内的时间集合
     *
     * @param startDate
     * @param endDate
     * @return List
     */
    public static List<Date> getDatesBetweenTwoDate(Date startDate, Date endDate) {
        List<Date> dates = new ArrayList<Date>();
        dates.add(startDate);// 把开始时间加入集合
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(startDate);
        while (true) {
            cal.add(Calendar.DAY_OF_MONTH, 1);
            if (endDate.after(cal.getTime()) && !DateUtils.isSameDay(endDate, cal.getTime())) {
                dates.add(cal.getTime());
            } else {
                break;
            }
        }
        if (startDate.compareTo(endDate) != 0) {
            dates.add(endDate);// 把结束时间加入集合
        }
        return dates;
    }

    /**
     * 获取时间段内的时间字符串集合
     *
     * @param startDate
     * @param endDate
     * @param dateFormat
     * @return
     */
    public static List<String> getDateCollection(Date startDate, Date endDate, String dateFormat) {

        if (dateFormat == null || StringUtils.equals(dateFormat, "")) {
            dateFormat = "yyyy-MM-dd";
        }
        List<String> dates = new ArrayList<String>();
        dates.add(DateUtil.convertDateToStr(startDate, dateFormat));
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(startDate);
        while (true) {
            cal.add(Calendar.DAY_OF_MONTH, 1);
            if (endDate.after(cal.getTime()) && !DateUtils.isSameDay(endDate, cal.getTime())) {
                dates.add(DateUtil.convertDateToStr(cal.getTime(), dateFormat));
            } else {
                break;
            }
        }
        dates.add(DateUtil.convertDateToStr(endDate, dateFormat));// 把结束时间加入集合
        return dates;
    }

    /**
     * 获得某个月的日期表格
     *
     * @param month
     * @return List
     */
    public static List<Date> getDateTab(Date month) {
        Date startDate = getFirstDayOfMonth(month);
        Date endDate = getLastDayOfMonth(month);
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(startDate);
        cal2.setTime(endDate);
        int i = cal1.get(Calendar.DAY_OF_WEEK);
        int j = cal2.get(Calendar.DAY_OF_WEEK);
        cal1.add(Calendar.DAY_OF_MONTH, -i + 1);
        cal2.add(Calendar.DAY_OF_MONTH, 7 - j);
        Date beforeDate = cal1.getTime();
        Date afterDate = cal2.getTime();
        return getDatesBetweenTwoDate(beforeDate, afterDate);
    }

    /**
     * 转化大写的月份（一月……十二月）为数字月份（01……12）
     *
     * @param chinaMonthName
     * @return
     */
    public static String convertMonthToNum(String chinaMonthName) {
        int i = ArrayUtils.indexOf(CHINA_MONTHS, chinaMonthName);
        return i > -1 ? YEAR_MONTHS[i] : "";
    }

    /**
     * 将两个时间根据指定天数分割为多个时间段
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param fate      每个时间段间隔的天数
     * @return 分割后的时间段:[[开始时间,结束时间],[开始时间,结束时间],...]
     */
    public static List<Date[]> toTimeSlot(Date startDate, Date endDate, Integer fate) {
        if (startDate == null || endDate == null) {
            /* 开始时间或结束时间为空返回空集合 */
            return new ArrayList<Date[]>();
        }
        List<Date[]> result = new ArrayList<Date[]>();
        /* 间隔天 */
        List<Date> days = getDatesBetweenTwoDate(startDate, endDate);
        /* 总天数 */
        Integer dayNumber = days.size();
        if (dayNumber < fate) {
            /* 如果间隔天数大于总天数则直接返回开始时间和结束时间 */
            result.add(new Date[]{
                    startDate, endDate
            });
        } else {
            /* 时间段个数 */
            Integer size = dayNumber / fate;
            /* 余数 */
            Integer remain = dayNumber % fate;
            if (remain > 0) {
                /* 余数大于零则将时间段个数加一 */
                size += 1;
            } else {
                /* 否则则将余数设置为间隔天数 */
                remain = fate;
            }
            /* 计算时间段 */
            for (int i = 1; i <= size; i++) {
                Integer start = i - 1;
                /* 时间段开始时间所在的索引 */
                Integer startIndex = start * fate;//+(start==0?0:1);
                /* 时间段结束时间所在的索引 */
                Integer endIndex = startIndex + fate;
                if (i == size) {
                    endIndex = startIndex + (remain - 1);
                }
                result.add(new Date[]{
                        days.get(startIndex),
                        days.get(endIndex - (start == 0 ? 1 : 0))// 如果当前是第一次遍历结束时间索引减一
                });
            }
        }
        return result;
    }

    /**
     * 获取指定时间的时间戳【毫秒】
     *
     * @param date
     * @return
     */
    public static Long getTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getTimeInMillis();
    }
}
